#include <memory>
#include <sys/epoll.h>
#include <wait.h>
#include <functional>
#include <sys/select.h>
#include "Common.hpp"
#include "Socket.hpp"
#define FDSIZE 1024
#define MAXEVENTS 128
int const fd_default = -1;
using namespace SocketMoudule;
using ioservice_t = function<void(shared_ptr<Socket> &, InetAddr &)>;
class TcpServer
{
public:
    TcpServer()
    {
        // 完成初始化（创建套接字、绑定端口、开启监听）...
        //......

        // 创建epoll模型
        _epfd = epoll_create(0);

        // 组织一个epoll_event变量，设置文件描述符和要关心的事件
        epoll_event event;
        event.data.fd = _listenfd;
        event.events = EPOLLIN | EPOLLET;

        // 将该文件信息设置到内核里
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, _listenfd, &event);
    }
    // 处理普通fd获取
    void SolveAccept()
    {
        InetAddr client;
        auto sock = _listensockptr->Accept(&client);
        epoll_event event;
        event.data.fd = sock->Fd();
        event.events = EPOLLIN;
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, sock->Fd(), &event);
        if (n < 0)
            LOG(Level::WARING) << "accept epoll_ctl fail";
        else
            LOG(Level::INFO) << "accept epoll_ctl success";
    }
    // 处理读数据
    void SolveRead(int fd)
    {
        char buffer[1024];
        int n = recv(fd, buffer, sizeof(buffer) - 1, 0);
        if (n == 0)
        {
            epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
            close(fd);
            cout << "client " << fd << " out..." << endl;
        }
        else if (n < 0)
        {
            epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
            close(fd);
            cout << "client " << fd << "recv fail" << endl;
        }
        else
        {
            buffer[n] = '\0';
            cout << "client say@: " << buffer << endl;
        }
    }
    void Start(ioservice_t callout)
    {
        _isrunning = true;
        while (_isrunning)
        {
            int tm = 1000;
            int n = epoll_wait(_epfd, _events, MAXEVENTS, tm);
            // 函数执行错误
            if (n < 0)
            {
                LOG(Level::WARING) << "epoll_wait fail\n";
            }
            // 超时
            else if (n == 0)
            {
                cout << "overtime..." << endl;
            }
            // 事件派发
            else
            {
                for (int i = 0; i < n; i++)
                {
                    if (_events[i].events | EPOLLIN)
                    {
                        if (_events[i].data.fd == _listensockptr->Fd())
                            SolveAccept();
                        else
                            SolveRead(_events[i].data.fd);
                    }
                }
            }
        }
    }

private:
    int _listenfd;
    int _epfd;
    struct epoll_event _events[MAXEVENTS];
    // 其他成员......
};

void HandlerEvent(int n)
{
    for (int i = 0; i < n; i++)
    {
        // 处理读事件就绪
        if (_events[i].events | EPOLLIN)
        {
            //_listenfd文件就绪
            if (_events[i].data.fd == _listenfd)
                SolveAccept();
            // 普通文件就绪
            else
                SolveRead(_events[i].data.fd);
        }
        // 处理其他事件就绪......
        //  else if(){}
    }
}
void Start(ioservice_t callout)
{
    _isrunning = true;
    while (_isrunning)
    {
        int tm = 1000; // 阻塞等待1000毫秒
        int n = epoll_wait(_epfd, _events, MAXEVENTS, tm);
        // 函数执行错误
        if (n < 0)
        {
            std::cout << "epoll_wait fail\n"
                      << std::endl;
            exit(1);
        }
        // 超时处理
        else if (n == 0)
        {
            std::cout << "overtime..." << std::endl;
        }
        // 事件派发
        else
        {
            std::cout << "事件就绪..." << std::endl;
            HandlerEvent(n);
        }
    }
}

// 处理读数据
void SolveRead(int userfd)
{
    char buffer[1024];
    int n = recv(userfd, buffer, sizeof(buffer) - 1, 0);
    if (n <= 0)
    {
        // recv返回值为0，用户断开连接；recv返回值为小于0，读取异常。
        // 这两种情况需要将userfd从内核中移除再关闭该文件。
        epoll_ctl(_epfd, EPOLL_CTL_DEL, userfd, nullptr);
        close(userfd);
    }
    else
    {
        buffer[n] = '\0';
        cout << "client say@: " << buffer << endl;
    }
}

#define MAXEVENTS 128
class TcpServer
{
public:
    TcpServer()
    {
        // 完成初始化（创建套接字、绑定端口、开启监听）...
        //......

        // 创建epoll模型
        _epfd = epoll_create(0);

        // 组织一个epoll_event变量，设置文件描述符和要关心的事件
        epoll_event event;
        event.data.fd = _listenfd;
        event.events = EPOLLIN | EPOLLET; // 设置ET模式和关心读事件

        // 将该文件信息设置到内核里
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, _listenfd, &event);
    }

private:
    int _listenfd;
    int _epfd;
    struct epoll_event _events[MAXEVENTS];
    // 其他成员......
};

void Start()
{
    while (true)
    {
        int tm = 1000;//阻塞等待1000毫秒
        int n = epoll_wait(_epfd, _events, MAXEVENTS, tm);;
        if (n > 0)
        {
            for (int i = 0; i < n; i++)
            {
                int fd = _events[i].data.fd;
                uint32_t event = _events[i].events;
                //不确定是什么错误，把event都设为读写就绪，让它们在函数内处理
                if (event & EPOLLERR) 
                    event |= (EPOLLIN | EPOLLOUT);
                if (event & EPOLLIN)
                {
                    if(fd == _listenfd)
                        SolveAccept();//_listenfd读事件处理
                    else 
                        Recver(fd);//普通文件读事件处理
                    
                }
                if (event & EPOLLOUT)
                {
                    Sender(fd);//普通文件读事件处理
                }
            }
        }
        // 超时处理
        else if (n == 0)
        {
            std::cout << "overtime..." << std::endl;
        }
        // 函数执行错误
        else
        {
            std::cout << "epoll_wait fail\n" << std::endl;
            exit(-1);
        }
    }
}

void SolveAccept()
{
    // accept获取到普通文件描述符记为userfd......
    epoll_event event;
    event.data.fd = userfd;
    event.events = EPOLLIN | EPOLLIN | EPOLLOUT; // 设为ET模式和关心读写事件
    int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, userfd, &event);
    //默认写事件是就绪的，所以这里可以直接调Recver，也可以让epoll模型触发。
    //......
}

void Recver(int userfd)
{
    char buffer[1024];
    while (true)
    {
        // 循环读取数据
        buffer[0] = 0;
        int n = recv(userfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            // 读取成功，数据处理......
        }
        else if (n == 0)
        {
            // recv返回值为0，说明用户断开连接，需要将userfd从内核中移除再关闭该文件。
            epoll_ctl(_epfd, EPOLL_CTL_DEL, userfd, nullptr);
            close(userfd);
            break;
        }
        else
        {
            // 如果因为底层没数据了，退出循环
            if (errno == EAGAIN || errno == EWOULDBLOCK)
                break;
            // 如果因为处理信号被打断，进行continue
            else if (errno == EINTR)
                continue;
            else
            {
                // 异常处理......
                return;
            }
        }
    }
}
void Sender(int userfd)
{
    while (true)
    {
        // 发送数据
        int n = send(userfd, /*......*/);
        if (n > 0)
        {
            // 发送成功处理......
        }
        else if (n == 0)
        {
            // 返回 0 说明操作成功完成，但请求发送的字节数为0（即没有数据需要发送了）
            break;
        }
        else
        {
            // 如果写事件未就绪（即发送缓冲区满了）则退出循环。
            if (errno == EAGAIN || errno == EWOULDBLOCK)
                break;
            // 如果因为处理信号被打断则进行continue
            else if (errno == EINTR)
                continue;
            else
            {
                // 异常处理......
                return;
            }
        }
    }
}